package org.lord.slark.numbers.fragments;

import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v7.app.AlertDialog;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.SearchView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;

import org.lord.slark.numbers.R;
import org.lord.slark.numbers.activity.AddSaintActivity;
import org.lord.slark.numbers.activity.SaintDetail;
import org.lord.slark.numbers.db.LocalDB;
import org.lord.slark.numbers.entity.Saint;
import org.lord.slark.numbers.utils.ELog;
import org.lord.slark.numbers.utils.LocalConstants;
import org.lord.slark.numbers.utils.SaintsTools;

import java.util.ArrayList;
import java.util.List;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link FragmentSaints.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link FragmentSaints#newInstance} factory method to
 * create an instance of this fragment.
 */
public class FragmentSaints extends ListFragment implements View.OnClickListener {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;
    private ImageView imgadd;
    private List<Saint> mList = new ArrayList<Saint>();
    private ListView mListView;
    private SaintAdapter mAdapter;
    private RadioButton btnactive, btnall;
    private SearchView searchview;

    private OnFragmentInteractionListener mListener;

    public FragmentSaints() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment FragmentSaints.
     */
    // TODO: Rename and change types and number of parameters
    public static FragmentSaints newInstance(String param1, String param2) {
        FragmentSaints fragment = new FragmentSaints();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    /**
     * Called when the fragment's activity has been created and this
     * fragment's view hierarchy instantiated.  It can be used to do final
     * initialization once these pieces are in place, such as retrieving
     * views or restoring state.  It is also useful for fragments that use
     * {@link #setRetainInstance(boolean)} to retain their instance,
     * as this callback tells the fragment when it is fully associated with
     * the new activity instance.  This is called after {@link #onCreateView}
     * and before {@link #onViewStateRestored(Bundle)}.
     *
     * @param savedInstanceState If the fragment is being re-created from
     *                           a previous saved state, this is the state.
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //getSaintList();
        mAdapter = new SaintAdapter();
        setListAdapter(mAdapter);
        mListView = getListView();
        mListView.setTextFilterEnabled(true);
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Saint saint = mList.get(position);
                Intent i = new Intent(getActivity(), SaintDetail.class);
                i.putExtra(LocalConstants.SAINT, saint);
                startActivity(i);
            }
        });
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    private void getSaintList() {
        mList.clear();
        SQLiteDatabase db = LocalDB.getInstance(getActivity()).getWritableDatabase();
        try {
            db.beginTransaction();
            Cursor c = db.query(Saint.TABLE_NAME, null, null, null, null, null, Saint.COLUMN_NAME + " asc");
            while (c.moveToNext()) {
                Saint saint = new Saint();
                saint.setName(c.getString(c.getColumnIndex(Saint.COLUMN_NAME)));
                saint.setPhone(c.getString(c.getColumnIndex(Saint.COLUMN_PHONE)));
                saint.setGender(c.getInt(c.getColumnIndex(Saint.COLUMN_GENDER)));
                saint.setIsBaptized(c.getInt(c.getColumnIndex(Saint.COLUMN_IS_BAPTIZED)));
                saint.setId(c.getInt(c.getColumnIndex(Saint.COLUMN_ID)));
                mList.add(saint);
            }
            db.setTransactionSuccessful();
            db.endTransaction();
            c.close();
            SaintsTools.sort(mList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            db.close();
        }
    }

    private void deleteSaintFromDB(Saint saint) {
        SQLiteDatabase db = LocalDB.getInstance(getActivity()).getWritableDatabase();
        try {
            db.delete(Saint.TABLE_NAME, Saint.COLUMN_ID + " = ?", new String[]{String.valueOf(saint.getId())});
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            db.close();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_saints, container, false);
        imgadd = (ImageView)v.findViewById(R.id.imgadd);
        btnactive = (RadioButton) v.findViewById(R.id.btnactive);
        btnall = (RadioButton) v.findViewById(R.id.btnall);
        searchview = (SearchView) v.findViewById(R.id.searchview);
        searchview.setIconifiedByDefault(false);
        searchview.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                mListView.setFilterText(newText);
                return true;
            }
        });
        imgadd.setOnClickListener(this);
        btnactive.setOnClickListener(this);
        btnall.setOnClickListener(this);
        return v;
    }

    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.imgadd:
                Intent addSaint = new Intent(getActivity(), AddSaintActivity.class);
                startActivity(addSaint);
                break;
            case R.id.btnactive:
                btnactive.setTextColor(Color.parseColor("#00BAD2"));
                btnall.setTextColor(Color.BLACK);
                break;
            case R.id.btnall:
                btnactive.setTextColor(Color.BLACK);
                btnall.setTextColor(Color.parseColor("#00BAD2"));
                break;
            default:
                break;
        }
    }

    /**
     * Called when the fragment is visible to the user and actively running.
     * This is generally
     * tied to {@link Activity#onResume() Activity.onResume} of the containing
     * Activity's lifecycle.
     */
    @Override
    public void onResume() {
        super.onResume();
        getSaintList();
        mAdapter.notifyDataSetChanged();
    }

    private class SaintAdapter extends BaseAdapter implements Filterable {
        private final Object mLock = new Object();
        /**
         * How many items are in the data set represented by this Adapter.
         *
         * @return Count of items.
         */
        @Override
        public int getCount() {
            return mList.size();
        }

        /**
         * Get the data item associated with the specified position in the data set.
         *
         * @param position Position of the item whose data we want within the adapter's
         *                 data set.
         * @return The data at the specified position.
         */
        @Override
        public Object getItem(int position) {
            return mList.get(position);
        }

        /**
         * Get the row id associated with the specified position in the list.
         *
         * @param position The position of the item within the adapter's data set whose row id we want.
         * @return The id of the item at the specified position.
         */
        @Override
        public long getItemId(int position) {
            return position;
        }

        /**
         * <p>Returns a filter that can be used to constrain data with a filtering
         * pattern.</p>
         * <p/>
         * <p>This method is usually implemented by {@link Adapter}
         * classes.</p>
         *
         * @return a filter used to constrain data
         */
        @Override
        public Filter getFilter() {
            return new MyFilter();
        }

        /**
         * Get a View that displays the data at the specified position in the data set. You can either
         * create a View manually or inflate it from an XML layout file. When the View is inflated, the
         * parent View (GridView, ListView...) will apply default layout parameters unless you use
         * {@link LayoutInflater#inflate(int, ViewGroup, boolean)}
         * to specify a root view and to prevent attachment to the root.
         *
         * @param position    The position of the item within the adapter's data set of the item whose view
         *                    we want.
         * @param convertView The old view to reuse, if possible. Note: You should check that this view
         *                    is non-null and of an appropriate type before using. If it is not possible to convert
         *                    this view to display the correct data, this method can create a new view.
         *                    Heterogeneous lists can specify their number of view types, so that this View is
         *                    always of the right type (see {@link #getViewTypeCount()} and
         *                    {@link #getItemViewType(int)}).
         * @param parent      The parent that this view will eventually be attached to
         * @return A View corresponding to the data at the specified position.
         */
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            final Saint saint = mList.get(position);
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(getActivity()).inflate(R.layout.saints_list_item, null);
                //holder.imgedit = (ImageView) convertView.findViewById(R.id.imgedit);
                //holder.imgdelete = (ImageView) convertView.findViewById(R.id.imgdelete);
                holder.tvname = (TextView) convertView.findViewById(R.id.tvname);
                holder.tvphone = (TextView) convertView.findViewById(R.id.tvphone);
                //holder.tvgender = (TextView) convertView.findViewById(R.id.tvgender);
                /*holder.imgedit.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent i = new Intent(getActivity(), AddSaintActivity.class);
                        i.putExtra(LocalConstants.SAINT, saint);
                        startActivity(i);
                    }
                });*/
                /*holder.imgdelete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        new AlertDialog.Builder(getActivity()).setMessage(getString(R.string.deletetoast))
                                .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        deleteSaintFromDB(mList.get(position));
                                        mList.remove(position);
                                        mAdapter.notifyDataSetChanged();
                                    }
                                }).setNegativeButton(getString(R.string.cancel), null).create().show();
                    }
                });*/
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            //holder.imgedit.setImageResource(R.mipmap.edit);
            //holder.imgdelete.setImageResource(R.mipmap.delete);
            holder.tvname.setText(saint.getName());
            holder.tvphone.setText(saint.getPhone());
            return convertView;
        }

        private class MyFilter extends Filter {
            /**
             * <p>Creates a new asynchronous filter.</p>
             */
            public MyFilter() {
                super();
            }

            /**
             * <p>Invoked in a worker thread to filter the data according to the
             * constraint. Subclasses must implement this method to perform the
             * filtering operation. Results computed by the filtering operation
             * must be returned as a {@link FilterResults} that
             * will then be published in the UI thread through
             * {@link #publishResults(CharSequence,
             * FilterResults)}.</p>
             * <p/>
             * <p><strong>Contract:</strong> When the constraint is null, the original
             * data must be restored.</p>
             *
             * @param constraint the constraint used to filter the data
             * @return the results of the filtering operation
             * @see #filter(CharSequence, FilterListener)
             * @see #publishResults(CharSequence, FilterResults)
             * @see FilterResults
             */
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint == null || constraint.length() == 0) {
                    synchronized (mLock) {
                        getSaintList();
                        ArrayList<Saint> list = new ArrayList<Saint>(mList);
                        filterResults.values = list;
                        filterResults.count = list.size();
                    }
                } else {
                    String searchString = constraint.toString().toLowerCase();
                    final ArrayList<Saint> newlist = new ArrayList<Saint>(mList.size());
                    for (Saint saint:mList) {
                        if (saint.getName().contains(searchString) || saint.getPhone().contains(searchString)) {
                            newlist.add(saint);
                        }
                    }
                    filterResults.values = newlist;
                    filterResults.count = newlist.size();
                }
                return filterResults;
            }

            /**
             * <p>Invoked in the UI thread to publish the filtering results in the
             * user interface. Subclasses must implement this method to display the
             * results computed in {@link #performFiltering}.</p>
             *
             * @param constraint the constraint used to filter the data
             * @param results    the results of the filtering operation
             * @see #filter(CharSequence, FilterListener)
             * @see #performFiltering(CharSequence)
             * @see FilterResults
             */
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mList = (ArrayList<Saint>) results.values;
                if (results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        }

    }
    private static class ViewHolder {
        //ImageView imgedit;
        //ImageView imgdelete;
        TextView tvname;
        TextView tvphone;
        //TextView tvgender;
    }
    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p/>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}
